package com.koi.web.controller.demo.test;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.koi.common.anno.*;
import com.koi.common.ex.koi.YUtil;
import com.koi.common.redis.RedisUtil;
import com.koi.common.tree.TreeTable;
import com.koi.common.tree.TreeTableUtil;
import com.koi.common.utils.i18n.I18nUtil;
import com.koi.plus.mapper.system.SysLoginUserMapper;
import com.koi.pojo.system.SysLoginUser;
import com.koi.web.enums.ResultStatusEnumA;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.ip2region.core.Ip2regionSearcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author ･ᴗ･
 * @description [IndexController]
 */
@Slf4j
@SaIgnore
@RequestMapping("/koi")
@RestController
public class IndexController {

    @Resource
    private SysLoginUserMapper loginUserMapper;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    // 地理位置
    @Autowired
    private Ip2regionSearcher ip2regionSearcher;

    // 国际化
    @Autowired
    private MessageSource messageSource;

    @Autowired
    private RedisUtil redisUtil;

    /**
     @AllArgsConstructor AND @RequiredArgsConstructor区别：
     @AllArgsConstructor 生成一个包含所有字段的构造方法, 如果使用了@Value注入，@Value注入会失效，原因时因为@Value注解是通过对象的set方法赋值的，构造方法的执行还在set方法之前，所以在构造方法中使用变量会变量为null。
     @RequiredArgsConstructor会将类的每一个final字段或者non-null字段生成一个构造方法 总结:@AllArgsConstructor和@RequiredArgsConstructor都可以用来替代@Autowired写法，区别在于@RequiredArgsConstructor必须要有final修饰，如果有@Value注解，@RequiredArgsConstructor修饰可以成功注入，@AllArgsConstructor修饰会注入失败
     */

    /**
     * @description [测试统一返回异常】
     * @author ･ᴗ･
     */
    @GetMapping("/resultEx")
    public String enableResultEx() {
        if (true) {
            //throw new OrderException(501,"@EnableResultEx测试成功");
            YUtil.isTrue(true, "小锦鲤跃龙门");
            return "@EnableResultEx测试失败";
        } else {
            return "@EnableResultEx测试失败";
        }
    }

    /**
     * @description [MybatisPlus分页测试]
     * @author ･ᴗ･
     */
    @KoiDictClass
    @GetMapping("/mp/{pageNum}/{pageSize}")
    public List<SysLoginUser> listUserForPage(@PathVariable("pageNum") Integer pageNum, @PathVariable("pageSize") Integer pageSize) {
        Page<SysLoginUser> page = new Page<>(pageNum, pageSize);
        loginUserMapper.selectPage(page, null);
        return page.getRecords();
    }

    /**
     * @description [限流测试]
     * @author ･ᴗ･
     */
    @KoiLimit(count = 3)
    @GetMapping("/koiLimit/{param}")
    public String koiLimit(@PathVariable("param") String param) {
        return "限流提交测试" + param;
    }

    /**
     * @description [重复提交测试-value单位毫秒]
     * @author ･ᴗ･
     */
    @KoiRepeatSubmit(value = 3000)
    @GetMapping("/koiRepeatSubmit/{param}")
    public String koiRepeatSubmit(@PathVariable("param") String param) {
        return "重复提交测试" + param;
    }

    /**
     * @description [测试枚举统一返回异常1]
     * @author ･ᴗ･
     */
    @GetMapping("resultEnumEx")
    public void resultEnumEx() {
        YUtil.isTrue(true, ResultStatusEnumA.USER_PWD_STATUS);
    }


    /**
     * @description [测试枚举统一返回异常2]
     * @author ･ᴗ･
     */
    @GetMapping("resultEnumEx2")
    public void resultEnumEx2() {
        YUtil.isTrue(true, ResultStatusEnumA.USER_PWD_STATUS_INPUT);
    }

    /**
     * @description [测试枚举统一返回异常3]
     * @author ･ᴗ･
     */
    @KoiLog()
    @GetMapping("/resultEnumEx3")
    public void resultEnumEx3() {
        YUtil.isTrue(false, ResultStatusEnumA.USER_PWD_STATUS_INPUT);
    }

    /**
     * @description [测试枚举统一返回异常4]
     * @author ･ᴗ･
     */
    @KoiLimit(time = 10, count = 2)
    @GetMapping("/resultEnumEx4")
    public String resultEnumEx4() {
        List<String> list = new ArrayList<>();
        list.add("11111哈哈哈哈哈");
        list.add("22222哈哈哈哈哈");
        list.add("33333哈哈哈哈哈");
        redisUtil.setCacheObject("testRedis:192.168.168.222:getTest1:", list, 180, TimeUnit.SECONDS);
        redisUtil.setCacheObject("testRedis:192.168.168.222:getTest2:", "wo是个、、、天才煩煩煩", 180, TimeUnit.SECONDS);
        return "resultEnumEx4";
    }

    /**
     * @description [测试]
     * @author ･ᴗ･
     */
    @GetMapping("/getTestApi")
    public String getTestApi() {
        log.info("getTestApi：{}", "getTestApi");
        return "getTestApi";
    }

    /**
     * @description [主库测试]
     * @author ･ᴗ･
     */
    @DS("master")
    @GetMapping("/dataSourceMaster")
    public String test1() {
        return jdbcTemplate.queryForObject("SELECT login_name FROM sys_login_user WHERE user_id = 1", String.class);
    }

    /**
     * @description [从库测试]
     * @author ･ᴗ･
     */
    @DS("slave")
    @GetMapping("/dataSourceSlave")
    public String test2() {
        return jdbcTemplate.queryForObject("select phone from koi_user where phone = 18593114301", String.class);
    }

    /**
     * @description [根据Ip获取地理位置]
     * @author ･ᴗ･
     */
    @GetMapping("/ip2regionSearcher")
    public String test3() {
        return ip2regionSearcher.getAddress("192.168.227.1");
    }

    /**
     * @description [无限层级树形表格测试]
     * @author ･ᴗ･
     */
    @GetMapping("/treeTableList")
    public List<TreeTable> treeTableList() {
        List<TreeTable> treeTableList = new ArrayList<>();
        TreeTable bo1 = new TreeTable();
        TreeTable bo2 = new TreeTable();
        TreeTable bo3 = new TreeTable();
        TreeTable bo4 = new TreeTable();
        TreeTable bo5 = new TreeTable();
        TreeTable bo6 = new TreeTable();
        bo1.setId("1");
        bo1.setLabel("A");
        bo1.setParentId("0");
        bo2.setId("2");
        bo2.setLabel("AA");
        bo2.setParentId("1");
        bo3.setId("3");
        bo3.setLabel("AAA");
        bo3.setParentId("2");
        bo4.setId("4");
        bo4.setLabel("AAAA");
        bo4.setParentId("3");
        bo5.setId("5");
        bo5.setLabel("B");
        bo5.setParentId("0");
        bo6.setId("6");
        bo6.setLabel("BB");
        bo6.setParentId("5");
        treeTableList.add(bo1);
        treeTableList.add(bo2);
        treeTableList.add(bo3);
        treeTableList.add(bo4);
        treeTableList.add(bo5);
        treeTableList.add(bo6);
        return TreeTableUtil.makeTree(treeTableList);
    }

    /**
     * 通过code获取国际化内容（乱码问题）
     * code为 messages.properties 中的 key
     * PostMan请求头中需要使用content-language en_US，因为resultex模块中进行了配置
     */
    @GetMapping("/getMessageByKey/{code}")
    public String getMessageByKey(@PathVariable("code") String code) {
        log.info("i18n：{}", I18nUtil.get("login.username"));
        return messageSource.getMessage(code, new Object[]{}, LocaleContextHolder.getLocale());
    }

    /**
     * 通过code获取国际化内容（乱码问题）
     * code为 messages.properties 中的 key
     * PostMan请求头中需要使用content-language en_US，因为resultex模块中进行了配置
     */
    @GetMapping("/getMessageByKeyForm")
    public String getMessageByKeyForm(@Validated DemoBo bo) {
        // 获取当前请求的区域Locale
        // Locale locale = LocaleContextHolder.getLocale();
        // messageSource.getMessage("language", null, locale);
        return "success";
    }

    /**
     * @description [序列化测试]
     * @author ･ᴗ･
     */
    @GetMapping("/demo")
    public DemoBo demo() {
        DemoBo demo = new DemoBo();
        // 被序列化位字符串
        demo.setNumber1(1234567891234567891L);
        demo.setNumber2(1987654321987654321L);
        // 依旧为数值
        demo.setNumber3(55555555555L);
        demo.setNumber4(1L);
        return demo;
    }

    /**
     * @description [测试登录]
     * 测试登录，浏览器访问： 使用 @PathParam("username") 是这种访问方式 http://localhost:8088/user/doLogin?username=zhang&password=123456
     * @author ･ᴗ･
     */
    @GetMapping("/doLogin/{username}/{password}")
    public String doLogin(@PathVariable("username") String username, @PathVariable("password") String password) {
        // 此处仅作模拟示例，真实项目需要从数据库中查询数据进行比对
        if ("koi".equals(username) && "123456".equals(password)) {
            StpUtil.login(10001);
            return "登录成功";
        }
        return "登录失败";
    }

    /**
     * @description [查询Sa-Token登录状态]
     * @author ･ᴗ･
     */
    @GetMapping("/isLogin")
    public String isLogin() {
        // 获取当前会话的token值
        System.out.println("获取当前会话的token值：" + StpUtil.getTokenValue());
        // 获取当前`StpLogic`的token名称
        System.out.println("获取当前`StpLogic`的token名称：" + StpUtil.getTokenName());
        // 获取指定token对应的账号id，如果未登录，则返回 null
        System.out.println("获取指定token对应的账号id，如果未登录，则返回 null：" + StpUtil.getLoginIdByToken("ab5873fd-a471-4ac5-8cd1-8fe3a5632012"));
        // 获取当前会话剩余有效期（单位：s，返回-1代表永久有效）
        System.out.println("获取当前会话剩余有效期（单位：s，返回-1代表永久有效）：" + StpUtil.getTokenTimeout());
        // 获取当前会话的token信息参数
        System.out.println("获取当前会话的token信息参数：" + StpUtil.getTokenInfo());
        // 获取当前会话账号id, 并转化为`long`类型
        System.out.println("获取当前会话账号id, 并转化为`long`类型：" + StpUtil.getLoginIdAsLong());
        return "当前会话是否登录：" + StpUtil.isLogin();
    }

    /**
     * @description [Sa-Token注销]
     * @author ･ᴗ･
     */
    @GetMapping("/test/logout")
    public String logout() {
        StpUtil.logout(10001);
        return "已注销";
    }


}
